#include <iostream>
#include <sstream>
#include "../SyncMethod/DoNot.h"
#include "../SyncMethod/CriticalSection.h"
#include "../SyncMethod/Mutex.h"
#include "../SyncMethod/Semaphore.h"
#include "../SyncMethod/Event.h"


struct Thread_Parameters
{
	std::string expression;
	unsigned long term;

	Thread_Parameters( const char* _expression, unsigned long _term )
	{
		expression.assign( _expression );
		term = _term;
	}
};

#define MAX_THREAD_COUNT ( 5 )



bool g_running = true;
int g_share_index = 0;


//Sync::DoNot				g_Sync( "Do not" );
Sync::CriticalSection		g_Sync( "Critical section" );
//Sync::Mutex					g_Sync( "Mutex" );
//Sync::Semaphore				g_Sync( "Semaphore", 1, 2 );
//Sync::Event					g_Sync( "Event" );



//!-- print message and increase value
void function( const char* msg, int& val )
{
	std::cout << msg << val << std::endl;
	++val;
}


//!-- thread
void thread( void* param )
{
	while( g_running )
	{
		if( g_Sync.lock() )
		{
			function( ( (Thread_Parameters* )param)->expression.c_str(), g_share_index );		

			g_Sync.unlock();
		}

		Sleep( ( (Thread_Parameters*)param )->term );
	}
}


//!-- run process
bool run( int max_val )
{
	return ( g_running = !( max_val < g_share_index ) );
}


//!-- main
int main( int argc, char* argv[] )
{
	Thread_Parameters* tp[MAX_THREAD_COUNT] = 
	{
		new Thread_Parameters( "-- thread A.\t: ", 500 ),
		new Thread_Parameters( "-- thread B.\t: ",  50 ),
		new Thread_Parameters( "-- thread C.\t: ", 150 ),
		new Thread_Parameters( "-- thread D.\t: ", 300 ),
		new Thread_Parameters( "-- thread E.\t: ", 700 ),
	};
	

	g_Sync.initialize();


	int loop = 0;

	for( loop = 0; loop < MAX_THREAD_COUNT; ++loop )
	{
		CreateThread( 0, 0, (LPTHREAD_START_ROUTINE)thread, tp[loop], 0, 0 );
	}


	while( run( 100 ) );

	
	for( loop = 0; loop < MAX_THREAD_COUNT; ++loop )
	{
		delete tp[loop]; tp[loop] = 0;
	}

	g_Sync.release();


	return 1;
}










/*
#include <windows.h>
#include <stdio.h>

#define MAX_SEM_COUNT 10
#define THREADCOUNT 12

HANDLE ghSemaphore;
int g_share_index = 0;


DWORD WINAPI ThreadProc( LPVOID );

int main( void )
{
    HANDLE aThread[THREADCOUNT];
    DWORD ThreadID;
    int i;

    // Create a semaphore with initial and max counts of MAX_SEM_COUNT

    ghSemaphore = CreateSemaphore( 
        NULL,           // default security attributes
        MAX_SEM_COUNT,  // initial count
        MAX_SEM_COUNT,  // maximum count
        NULL);          // unnamed semaphore

    if (ghSemaphore == NULL) 
    {
        printf("CreateSemaphore error: %d\n", GetLastError());
        return 1;
    }

    // Create worker threads

    for( i=0; i < THREADCOUNT; i++ )
    {
        aThread[i] = CreateThread( 
                     NULL,       // default security attributes
                     0,          // default stack size
                     (LPTHREAD_START_ROUTINE) ThreadProc, 
                     NULL,       // no thread function arguments
                     0,          // default creation flags
                     &ThreadID); // receive thread identifier

        if( aThread[i] == NULL )
        {
            printf("CreateThread error: %d\n", GetLastError());
            return 1;
        }
    }

    // Wait for all threads to terminate

    WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);

    // Close thread and semaphore handles

    for( i=0; i < THREADCOUNT; i++ )
        CloseHandle(aThread[i]);

    CloseHandle(ghSemaphore);

    return 0;
}

DWORD WINAPI ThreadProc( LPVOID lpParam )
{

    // lpParam not used in this example
    UNREFERENCED_PARAMETER(lpParam);

    DWORD dwWaitResult; 
    BOOL bContinue=TRUE;

    while(bContinue)
    {
        // Try to enter the semaphore gate.

        dwWaitResult = WaitForSingleObject( 
            ghSemaphore,   // handle to semaphore
            0L);           // zero-second time-out interval

        switch (dwWaitResult) 
        { 
            // The semaphore object was signaled.
            case WAIT_OBJECT_0: 
                // TODO: Perform task
                printf("Thread %d: wait succeeded.\t%d\n", GetCurrentThreadId(), g_share_index );
				++g_share_index;
                bContinue=FALSE;            

                // Simulate thread spending time on task
                Sleep(5);

                // Release the semaphore when task is finished

                if (!ReleaseSemaphore( 
                        ghSemaphore,  // handle to semaphore
                        1,            // increase count by one
                        NULL) )       // not interested in previous count
                {
                    printf("ReleaseSemaphore error: %d\n", GetLastError());
                }
                break; 

            // The semaphore was nonsignaled, so a time-out occurred.
            case WAIT_TIMEOUT: 
                printf("Thread %d: wait timed out\n", GetCurrentThreadId());
                break; 
        }
    }
    return TRUE;
}
*/